﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OBUActivation.LOG;

namespace OBUActivation
{
    class ESAMProgress
    {
        public const string RESULT_ESAM_OPENFAIL = "ESAM开启失败！";

        private static SAMReader esamReader = null;

        private static string LINE_SEPARATOR = System.Environment.NewLine;

        /// <summary>
        /// 更新二进制文件中的数据,,除了DF03下的EF03是写入自由，其余都是明文加MAC
        /// </summary>
        /// <param name="dir">目录名，如DF03,DF04,MF根目录就用3F00表示</param>
        /// <param name="p1">文件号，如 80 + SFI，...</param>
        /// <param name="p2">低地址，开始更新位置</param>
        /// <param name="lc">Data域数据长度</param>
        /// <param name="data">明文数据</param>
        /// <returns>不同情况下的执行结果拼凑成的结果</returns>
        public static string UpdateBinary(string dir, byte p1, byte p2, byte lc, byte[] data, byte[] mac)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("更新二进制文件(dir=" + dir + ",p1=" + p1 + ",p2=" + p2 + ",lc=" + lc + "):" + LINE_SEPARATOR);
            SAMReader reader = GetEsamReader();
            if (reader != null)
            {
                //不是主目录，进入目录
                if (!dir.Equals("3F00"))
                {
                    byte[] selectFileCmd = ESAMCmd.SelectFile((ushort)Convert.ToInt16(dir, 16));
                    byte[] recvPacket = reader.SendCommand(selectFileCmd);
                    if (recvPacket[recvPacket.Length - 2] == 0x90 &&
                         recvPacket[recvPacket.Length - 1] == 0x00)
                    {
                        sb.Append("进入目录" + dir + "成功" + LINE_SEPARATOR);
                    }
                    else
                    {
                        sb.Append("进入目录" + dir + "失败" + LINE_SEPARATOR);
                        return sb.ToString();
                    }
                }

                byte[] packet, recvPacket1;

                packet = ESAMCmd.UpdateBinary(p1, p2, lc, data, mac);
                recvPacket1 = reader.SendCommand(packet);

                sb = FormatOutput(sb, packet, recvPacket1);

                byte[] responseCode = new byte[2];
                Array.Copy(recvPacket1, recvPacket1.Length - 2, responseCode, 0, 2);
                sb.Append("响应码:" + HexConverter.HexToStr(responseCode) + "\n");
                if (responseCode[0] == 0x90 && responseCode[1] == 0x00)
                {
                    sb.Append("更新二进制文件成功!" + LINE_SEPARATOR);
                }
                else if (responseCode[0] == 0x6A && responseCode[1] == 0x82)
                {
                    sb.Append("未找到文件!" + LINE_SEPARATOR);
                }
                else if (responseCode[0] == 0x69 && responseCode[1] == 0x81)
                {
                    sb.Append("当前文件不是二进制文件!" + LINE_SEPARATOR);
                }

                //退出目录，回到主目录
                if (!dir.Equals("3F00"))
                {
                    byte[] selectFileCmd = ESAMCmd.SelectFile(0x3F00);
                    recvPacket1 = reader.SendCommand(selectFileCmd);
                    if (recvPacket1[recvPacket1.Length - 2] == 0x90 &&
                            recvPacket1[recvPacket1.Length - 1] == 0x00)
                    {
                        sb.Append("退出目录" + dir + "成功" + LINE_SEPARATOR);
                    }
                    else
                    {
                        sb.Append("退出目录" + dir + "失败" + LINE_SEPARATOR);
                    }
                }


            }
            else
            {
                Log.i("UPDATE BINARY 获取读卡器失败!");
                sb.Append("获取读卡器失败!" + LINE_SEPARATOR);
            }
            sb.Append("-------------------------------------------------------------\n");
            return sb.ToString();
        }

        /// <summary>
        /// 请求一个永远全过程的随机数(包括4字节和8字节的随机数)
        /// </summary>
        /// <param name="b">随机数长度</param>
        /// <returns>回送的响应信息中可能出现的状</returns>
        public static string GetChallenge(byte b)
        {
            StringBuilder sb = new StringBuilder();
            SAMReader reader = GetEsamReader();
            sb.Append("获取" + b + "字节随机数:" + LINE_SEPARATOR);
            if (reader != null)
            {
                byte[] packet = ESAMCmd.GetChallenge(b);
                byte[] recvPacket = reader.SendCommand(packet);
                sb = FormatOutput(sb, packet, recvPacket);

                byte[] responseCode = new byte[2];
                Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);

                if (responseCode[0] == 0x90 && responseCode[1] == 0x00)
                {
                    sb.Append("响应码:9000" + LINE_SEPARATOR);
                    byte[] challenge = new byte[recvPacket.Length - 2];
                    Array.Copy(recvPacket, challenge, challenge.Length);
                    string challengeStr = HexConverter.HexToStr(challenge);
                    sb.Append("随机数:" + challengeStr + LINE_SEPARATOR);
                    Log.i("GET CHALLENGE(" + b + "): " + challengeStr);
                }
                else if (responseCode[0] == 0x67 && responseCode[1] == 0x00)
                {
                    sb.Append("响应码:6700" + LINE_SEPARATOR);
                    Log.i("获取随机数响应码:6700" + LINE_SEPARATOR);
                }
                else
                {
                    sb.Append("响应码:" + HexConverter.HexToStr(responseCode) + LINE_SEPARATOR);
                }

            }
            else
            {
                Log.i("GET CHALLENGE 获取读卡器失败!");
                sb.Append("GET CHALLENGE 获取读卡器失败!" + LINE_SEPARATOR);
            }

            sb.Append("-------------------------------------------------------------" + LINE_SEPARATOR);
            return sb.ToString();
        }

        /// <summary>
        /// 请求一个永远全过程的随机数(包括4字节和8字节的随机数)
        /// </summary>
        /// <param name="b">随机数长度</param>
        /// <returns>回送的响应信息中可能出现的状</returns>
        public static byte[] GetChallege(byte b)
        {
            SAMReader reader = GetEsamReader();
            if (reader != null)
            {
                byte[] packat = ESAMCmd.GetChallenge(b);
                byte[] recvPackat = reader.SendCommand(packat);
                byte[] responseCode = new byte[2];

                Array.Copy(recvPackat, recvPackat.Length - 2, responseCode, 0, 2);
                if (responseCode[0] == 0X90 && responseCode[1] == 0X00)
                {
                    byte[] challege = new byte[recvPackat.Length - 2];
                    Array.Copy(recvPackat, 0, challege, 0, challege.Length);
                    return challege;
                }
                else
                {
                    Log.i("GET CHALLENGE 失败!");
                    return null;
                }
            }
            else
            {
                Log.i("获取读卡器失败!");
                return null;
            }
        }

        /// <summary>
        /// 读取系统信息文件
        /// </summary>
        /// <param name="len">期望读取的信息数据明文长度</param>
        /// <param name="keyVersion">密钥版本</param>
        /// <returns></returns>
        //public static string ReadSystemInfoData(byte len, byte keyVersion)
        //{
        //    StringBuilder sb = new StringBuilder();
        //    sb.Append("读取系统信息文件:\n");
        //    SAMReader reader = GetEsamReader();
        //    if (reader != null)
        //    {
        //        //随机数为0
        //        byte[] packet = ESAMCmd.ReadSystemInfoData(0, len, keyVersion);
        //        byte[] recvPacket = reader.SendCommand(packet);

        //        string input = HexConverter.HexToStr(packet);
        //        string output = HexConverter.HexToStr(recvPacket, recvPacket.Length - 2);
        //        sb.Append("发送报文:" + input + LINE_SEPARATOR);
        //        sb.Append("接受报文(密文):" + output + LINE_SEPARATOR);
        //        DataRecordUtil.record("读系统信息文件", input, "（密文）" + output);
        //        byte[] responseCode = new byte[2];
        //        Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);
        //        if (responseCode[0] == 0x90 && responseCode[1] == 0x00)
        //        {
        //            return output;
        //        }
        //        else
        //        {
        //            DataRecordUtil.record("读系统信息文件", input, "响应码：" + HexConverter.HexToStr(responseCode));
        //            sb.Append("响应吗:" + HexConverter.HexToStr(responseCode) + "\n");
        //            sb.Append("-------------------------------------------------------------\n");
        //            return sb.ToString();
        //        }

        //    }
        //    else
        //    {
        //        Log.e("Read System Info Data 获取读卡器失败!");
        //        sb.Append("获取读卡器失败!\n");
        //        sb.Append("-------------------------------------------------------------\n");
        //        return sb.ToString();
        //    }
        //}

        /// <summary>
        /// 读取系统信息文件
        /// </summary>
        /// <param name="len">期望读取的信息数据明文长度</param>
        /// <param name="keyVersion">密钥版本</param>
        /// <returns></returns>
        public static byte[] ReadSystemInfoData(byte len, byte keyVersion)
        {
            SAMReader reader = GetEsamReader();
            if (reader != null)
            {
                //随机数为0
                byte[] packet = ESAMCmd.ReadSystemInfoData(0, len, keyVersion);
                byte[] recvPacket = reader.SendCommand(packet);
                byte[] responseCode = new byte[2];
                Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);
                if (responseCode[0] == 0X90 && responseCode[1] == 00)
                {
                    byte[] systemInfoData = new byte[recvPacket.Length - 2];
                    return systemInfoData;
                }
                else
                {
                    Log.i("ReadSystemInfoData 失败");
                    return null;
                }
            }
            else
            {
                Log.i("获取读卡器失败!");
                return null;
            }
        }

        /// <summary>
        /// 专有命令 GET AUTHENTICATION （收费交易模式二及稽查交易模式）
        /// </summary>
        /// <param name="keyVersion">密钥版本号（对于密钥版本数）</param>
        /// <returns></returns>
        //public static string GetAuthentication(byte keyVersion)
        //{
        //    SAMReader reader = GetEsamReader();

        //    StringBuilder sb = new StringBuilder();
        //    sb.Append("专有命令 GET AUTHENTICATION 测试");
        //    sb.Append(System.Environment.NewLine);

        //    if (reader == null)
        //    {
        //        return RESULT_ESAM_OPENFAIL;
        //    }

        //    byte[] recv, cmd;

        //    // GET AUTHENTICATION 授权
        //    cmd = ESAMCmd.GetAuthentication(null, keyVersion);
        //    recv = reader.SendCommand(cmd);
        //    byte[] responseCode = new byte[2];
        //    Array.Copy(recv, recv.Length - 2, responseCode, 0, 2);
        //    sb.Append(FormatReturn("1、GET AUTHENTICATION 授权对BST中随机数进行加密",
        //            HexConverter.HexToStr(cmd),
        //            HexConverter.HexToStr(recv, recv.Length - 2),
        //            HexConverter.HexToStr(responseCode), ""));
        //    if (responseCode[0] != 0x90 && responseCode[1] != 0x00)
        //    {
        //        return sb.ToString();
        //    }

        //    sb.Append("授权码为：" + HexConverter.HexToStr(recv, 8));
        //    return sb.ToString();
        //}

        /// <summary>
        /// 专有命令 GET AUTHENTICATION （收费交易模式二及稽查交易模式）
        /// </summary>
        /// <param name="random">收到的随机数</param>
        /// <param name="keyVersion">密钥版本号</param>
        /// <returns></returns>
        public static byte[] GetAuthentication(byte[] random, byte keyVersion)
        {
            SAMReader reader = GetEsamReader();
            if (reader != null)
            {
                byte[] packet = ESAMCmd.GetAuthentication(random, keyVersion);
                byte[] recvPacket = reader.SendCommand(packet);
                byte[] responseCode = new byte[2];
                Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);
                if (responseCode[0] == 0X90 && responseCode[1] == 0X00)
                {
                    byte[] authen = new byte[recvPacket.Length - 2];
                    Array.Copy(recvPacket, 0, authen, 0, authen.Length);
                    return authen;
                }
                else
                {
                    Log.i("GetAuthentication 失败!");
                    return null;
                }
            }
            else
            {
                Log.i("获取读卡器失败!");
                return null;
            }
        }

        /// <summary>
        /// 获取OBUMAC
        /// </summary>
        /// <param name="len"></param>
        /// <param name="keyVersion"></param>
        /// <returns></returns>
        //public static string GetOBUMAC(byte len, byte keyVersion)
        //{
        //    string OBUMAC = null;
        //    string output = ReadSystemInfoData(len, keyVersion);
        //    byte[] output1 = SamUtil.ConvertString2Array(output);
        //    byte[] OBUMac = new byte[4];
        //    Array.Copy(output1, 27, OBUMac, 0, 4);
        //    OBUMAC = SamUtil.ConvertArray2HexString(OBUMac);
        //    return OBUMAC;
        //}

        /// <summary>
        /// 获取OBUMAC
        /// </summary>
        /// <param name="len"></param>
        /// <param name="keyVersion"></param>
        /// <returns></returns>
        public static byte[] GetOBUMAC(byte len,byte keyVersion)
        {
            byte[] output = ReadSystemInfoData(len, keyVersion);
            byte[] OBUMac = new byte[4];
            Array.Copy(output, 27, OBUMac, 0, 4);
            return OBUMac;
        }

        /// <summary>
        /// 获取OBU拆卸状态
        /// </summary>
        /// <param name="len"></param>
        /// <param name="keyVersion"></param>
        /// <returns></returns>
        public static byte GetTamperedInfo(byte len, byte keyVersion)
        {
            byte[] output = ReadSystemInfoData(len, keyVersion);
            byte tampered = output[31];
            return tampered;
        }

        /// <summary>
        /// 获取合同序列号
        /// </summary>
        //public static string GetContractNum()
        //{
        //    string contractNum = null;

        //    if (contractNum == null)
        //    {
        //        if (GetEsamReader() != null)
        //        {
        //            byte[] sendPacket = ESAMCmd.GetCipherData();
        //            byte[] recvPacket = esamReader.SendCommand(sendPacket);//密文

        //            byte[] responseCode = new byte[2];
        //            Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);

        //            if (responseCode[0] == 0X90 && responseCode[1] == 0X00)
        //            {
        //                String output = HexConverter.HexToStr(recvPacket, recvPacket.Length - 2);
        //                //0-7个字节为合同序列号
        //                contractNum = output.Substring(0, 8);
        //                Log.i("获取合同序列号：" + contractNum);

        //            }
        //            else
        //            {
        //                Log.e("获取合同序列号发生错误，响应码：" + HexConverter.HexToStr(responseCode));
        //            }
        //        }
        //    }

        //    return contractNum;
        //}

        public static byte[] GetContractNum()
        {
            SAMReader reader = GetEsamReader();
            if (reader != null)
            {
                byte[] packet = ESAMCmd.GetCipherData();
                byte[] recvPacket = reader.SendCommand(packet);
                byte[] responseCode = new byte[2];
                Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);
                if (responseCode[0] == 0X90 && responseCode[1] == 0X00)
                {
                    byte[] contractNum = new byte[recvPacket.Length - 2];
                    Array.Copy(recvPacket, 0, contractNum, 0, contractNum.Length);
                    return contractNum;
                }
                else
                {
                    Log.i("GetContractNum失败");
                    return null;
                }
            }
            else
            {
                Log.i("获取读卡器失败!");
                return null;
            }
        }

        /// <summary>
        /// 获取加密随机数
        /// </summary>
        /// <returns></returns>
        //public static string Get2Random()
        //{
        //    string strRandom = null;
        //    byte[] random = new byte[2];
        //    if (GetEsamReader() != null)
        //    {
        //        byte[] sendPacket = ESAMCmd.GetCipherData();
        //        byte[] recvPacket = esamReader.SendCommand(sendPacket);//密文

        //        byte[] responseCode = new byte[2];
        //        Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);

        //        if (responseCode[0] == 0X90 && responseCode[1] == 0X00)
        //        {
        //            String output = HexConverter.HexToStr(recvPacket, recvPacket.Length - 2);
        //            //0-7个字节为合同序列号
        //            strRandom = output.Substring(18, output.Length - 2);
        //            Log.i("获取合同序列号：" + contractNum);

        //        }
        //        else
        //        {
        //            Log.e("获取合同序列号发生错误，响应码：" + HexConverter.HexToStr(responseCode));
        //        }
        //    }

        //    return strRandom;
        //}

        /// <summary>
        /// 获取加密随机数
        /// </summary>
        /// <returns></returns>
        public static byte[] Get2Random()
        {
            SAMReader reader = GetEsamReader();
            if (reader != null)
            {
                byte[] packet = ESAMCmd.GetCipherData();
                byte[] recvPacket = reader.SendCommand(packet);
                byte[] responseCode = new byte[2];
                Array.Copy(recvPacket, recvPacket.Length - 2, responseCode, 0, 2);
                if (responseCode[0] == 0X90 && responseCode[1] == 0X00)
                {
                    byte[] random = new byte[2];
                    return random;
                }
                else
                {
                    Log.i("Get2Random失败");
                    return null;
                }
            }
            else
            {
                Log.i("获取读卡器失败!");
                return null;
            }
        }

        /// <summary>
        /// 获得ESAMReader实例
        /// </summary>
        /// <returns>Reader实例，获取失败则返回null</returns>
        private static SAMReader GetEsamReader()
        {
            if (esamReader == null)
            {
                SAMSetFactory samFactory = SAMSetFactory.GetInstance();
                ReaderSet rd_set = samFactory.Get(SAM_TYPE.ESAM);
                if (rd_set != null)
                {
                    esamReader = new ESAMReader();
                    esamReader.Open(rd_set);
                }
            }
            return esamReader;
        }

        /// <summary>
        /// 格式化输出
        /// </summary>
        /// <param name="sb">输入字符串</param>
        /// <param name="packet">发送报文</param>
        /// <param name="recvPacket">接收报文</param>
        /// <returns>拼凑后的字符串</returns>
        private static StringBuilder FormatOutput(StringBuilder sb, byte[] packet, byte[] recvPacket)
        {
            string input = HexConverter.HexToStr(packet);
            string output = HexConverter.HexToStr(recvPacket, recvPacket.Length - 2);
            sb.Append("发送报文:" + input + LINE_SEPARATOR).Append("接受报文:" + output + LINE_SEPARATOR);
            DataRecordUtil.record("DECREASE COUNTER", input, output);
            return sb;
        }

        /// <summary>
        /// 格式化输出
        /// </summary>
        /// <param name="cmdName">执行测试的命令名字</param>
        /// <param name="sendCmd">发送的报文</param>
        /// <param name="recvCmd">接收的报文</param>
        /// <param name="respCode">响应码</param>
        /// <param name="infoList">业务数据信息</param>
        /// <returns></returns>
        public static string FormatReturn(string cmdName, string sendCmd, string recvCmd, string respCode, string info)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append(cmdName);
            sb.Append(System.Environment.NewLine);
            sb.Append("发送报文：");
            sb.Append(sendCmd);
            sb.Append(System.Environment.NewLine);
            sb.Append("接收报文：");
            sb.Append(recvCmd);
            sb.Append(System.Environment.NewLine);
            sb.Append("响应码：");
            sb.Append(respCode);

            sb.Append(System.Environment.NewLine);
            sb.Append(info);

            return sb.ToString();
        }
    }
}
